NexusPi Git Node
tests/backend/test_database_provider_fd_oracle.py 786bddfe0aebae27a59e4e8aa7a87ae9a1163c12 (786bddfe) Text, 4.08 KB
T8b949e# SPDX-License-Identifier: 0BSD
T8b949e"""Oracle: DatabaseProvider must not close a live thread's SQLite handle."""
Tff7b72from T7ee787__future__ Tff7b72import Te6edf3annotations
Tff7b72import T7ee787os
Tff7b72import T7ee787sqlite3
Tff7b72import T7ee787tempfile
Tff7b72import T7ee787threading
Tff7b72import T7ee787pytest
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787databaseT7ee787.T7ee787provider Tff7b72import Te6edf3DatabaseProvider
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787databaseT7ee787.T7ee787sqlite_errors Tff7b72import Te6edf3sqlite_error_is_retryable
Tf0883e@pytestTff7b72.Td2a8fffixtureTb4b4b4(Te6edf3autouseTff7b72=Tff7b72TrueTb4b4b4)
Tff7b72def Td2a8ffreset_providerTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3DatabaseProviderTff7b72.Td2a8ff_instance Tff7b72= Tff7b72None
Tff7b72yield
Tff7b72if Te6edf3DatabaseProviderTff7b72.Td2a8ff_instance Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
Te6edf3DatabaseProviderTff7b72.Td2a8ff_instanceTff7b72.Td2a8ffclose_allTb4b4b4(Tb4b4b4)
Te6edf3DatabaseProviderTff7b72.Td2a8ff_instance Tff7b72= Tff7b72None
Tff7b72def Td2a8fftest_announce_style_threads_do_not_accumulate_connectionsTb4b4b4(Tb4b4b4)Tb4b4b4:
T8b949e"""RNS starts a Thread per announce callback that touches the DB.
After those threads exit, orphaned connections must be pruned so WAL FDs
cannot grow without bound (Docker Errno 24).
"""
Tff7b72with Te6edf3tempfileTff7b72.Td2a8ffTemporaryDirectoryTb4b4b4(Tb4b4b4) Tff7b72as Te6edf3temp_dirTb4b4b4:
Te6edf3db_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3temp_dirTb4b4b4, Ta5d6ff"Ta5d6ffannounces.dbTa5d6ff"Tb4b4b4)
Te6edf3provider Tff7b72= Te6edf3DatabaseProviderTb4b4b4(Te6edf3db_pathTb4b4b4)
Te6edf3providerTff7b72.Td2a8ffexecuteTb4b4b4(Ta5d6ff"Ta5d6ffCREATE TABLE t (id INTEGER PRIMARY KEY, val TEXT)Ta5d6ff"Tb4b4b4)
Te6edf3barrier Tff7b72= Te6edf3threadingTff7b72.Td2a8ffBarrierTb4b4b4(T79c0ff33Tb4b4b4)
Te6edf3errorsTb4b4b4: Tffa657listTb4b4b4[Tf85149BaseExceptionTb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72def Td2a8ffworkerTb4b4b4(Te6edf3nTb4b4b4: Tffa657intTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3providerTff7b72.Td2a8ffexecuteTb4b4b4(Ta5d6ff"Ta5d6ffINSERT INTO t (val) VALUES (?)Ta5d6ff"Tb4b4b4, Tb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffwTffd700{Te6edf3nTffd700}Ta5d6ff"Tb4b4b4,Tb4b4b4)Tb4b4b4)
Te6edf3barrierTff7b72.Td2a8ffwaitTb4b4b4(Te6edf3timeoutTff7b72=T79c0ff10Tb4b4b4)
Te6edf3barrierTff7b72.Td2a8ffwaitTb4b4b4(Te6edf3timeoutTff7b72=T79c0ff10Tb4b4b4)
Tff7b72except Tf85149BaseException Tff7b72as Te6edf3excTb4b4b4:
Te6edf3errorsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3excTb4b4b4)
Te6edf3threads Tff7b72= Tb4b4b4[Te6edf3threadingTff7b72.Td2a8ffThreadTb4b4b4(Te6edf3targetTff7b72=Te6edf3workerTb4b4b4, Te6edf3argsTff7b72=Tb4b4b4(Te6edf3iTb4b4b4,Tb4b4b4)Tb4b4b4) Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(T79c0ff32Tb4b4b4)Tb4b4b4]
Tff7b72for Te6edf3thread Tff7b72in Te6edf3threadsTb4b4b4:
Te6edf3threadTff7b72.Td2a8ffstartTb4b4b4(Tb4b4b4)
Te6edf3barrierTff7b72.Td2a8ffwaitTb4b4b4(Te6edf3timeoutTff7b72=T79c0ff10Tb4b4b4)
Te6edf3barrierTff7b72.Td2a8ffwaitTb4b4b4(Te6edf3timeoutTff7b72=T79c0ff10Tb4b4b4)
Tff7b72for Te6edf3thread Tff7b72in Te6edf3threadsTb4b4b4:
Te6edf3threadTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3timeoutTff7b72=T79c0ff5Tb4b4b4)
Tff7b72assert Tff7b72not Te6edf3threadTff7b72.Td2a8ffis_aliveTb4b4b4(Tb4b4b4)
Tff7b72assert Te6edf3errors Tff7b72== Tb4b4b4[Tb4b4b4]
Te6edf3pruned Tff7b72= Te6edf3providerTff7b72.Td2a8ffprune_orphaned_connectionsTb4b4b4(Tb4b4b4)
Tff7b72assert Te6edf3pruned Tff7b72>Tff7b72= T79c0ff1
T8b949e# Main thread still owns the connection from CREATE TABLE / setup.
Tff7b72assert Te6edf3providerTff7b72.Td2a8ffconnection_countTb4b4b4(Tb4b4b4) Tff7b72<Tff7b72= T79c0ff1
Tff7b72def Td2a8fftest_live_thread_keeps_working_during_announce_burstTb4b4b4(Tb4b4b4)Tb4b4b4:
T8b949e"""Cap-eviction used to close the HTTP worker's handle mid-request."""
Tff7b72with Te6edf3tempfileTff7b72.Td2a8ffTemporaryDirectoryTb4b4b4(Tb4b4b4) Tff7b72as Te6edf3temp_dirTb4b4b4:
Te6edf3db_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3temp_dirTb4b4b4, Ta5d6ff"Ta5d6ffburst.dbTa5d6ff"Tb4b4b4)
Te6edf3provider Tff7b72= Te6edf3DatabaseProviderTb4b4b4(Te6edf3db_pathTb4b4b4)
Te6edf3providerTff7b72.Td2a8ffexecuteTb4b4b4(Ta5d6ff"Ta5d6ffCREATE TABLE t (id INTEGER PRIMARY KEY, val TEXT)Ta5d6ff"Tb4b4b4)
Te6edf3hold Tff7b72= Te6edf3threadingTff7b72.Td2a8ffEventTb4b4b4(Tb4b4b4)
Te6edf3started Tff7b72= Te6edf3threadingTff7b72.Td2a8ffBarrierTb4b4b4(T79c0ff41Tb4b4b4)
Te6edf3errorsTb4b4b4: Tffa657listTb4b4b4[Tf85149BaseExceptionTb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72def Td2a8ffannounce_workerTb4b4b4(Te6edf3nTb4b4b4: Tffa657intTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3providerTff7b72.Td2a8ffexecuteTb4b4b4(Ta5d6ff"Ta5d6ffINSERT INTO t (val) VALUES (?)Ta5d6ff"Tb4b4b4, Tb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffaTffd700{Te6edf3nTffd700}Ta5d6ff"Tb4b4b4,Tb4b4b4)Tb4b4b4)
Te6edf3startedTff7b72.Td2a8ffwaitTb4b4b4(Te6edf3timeoutTff7b72=T79c0ff10Tb4b4b4)
Te6edf3holdTff7b72.Td2a8ffwaitTb4b4b4(Te6edf3timeoutTff7b72=T79c0ff10Tb4b4b4)
Te6edf3providerTff7b72.Td2a8ffexecuteTb4b4b4(Ta5d6ff"Ta5d6ffSELECT COUNT(*) FROM tTa5d6ff"Tb4b4b4)
Tff7b72except Tf85149BaseException Tff7b72as Te6edf3excTb4b4b4:
Te6edf3errorsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3excTb4b4b4)
Te6edf3threads Tff7b72= Tb4b4b4[Te6edf3threadingTff7b72.Td2a8ffThreadTb4b4b4(Te6edf3targetTff7b72=Te6edf3announce_workerTb4b4b4, Te6edf3argsTff7b72=Tb4b4b4(Te6edf3iTb4b4b4,Tb4b4b4)Tb4b4b4) Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(T79c0ff40Tb4b4b4)Tb4b4b4]
Tff7b72for Te6edf3thread Tff7b72in Te6edf3threadsTb4b4b4:
Te6edf3threadTff7b72.Td2a8ffstartTb4b4b4(Tb4b4b4)
Te6edf3startedTff7b72.Td2a8ffwaitTb4b4b4(Te6edf3timeoutTff7b72=T79c0ff10Tb4b4b4)
Te6edf3row Tff7b72= Te6edf3providerTff7b72.Td2a8fffetchoneTb4b4b4(Ta5d6ff"Ta5d6ffSELECT COUNT(*) AS n FROM tTa5d6ff"Tb4b4b4)
Tff7b72assert Te6edf3row Tff7b72is Tff7b72not Tff7b72None
Tff7b72assert Tffa657intTb4b4b4(Te6edf3rowTb4b4b4[Ta5d6ff"Ta5d6ffnTa5d6ff"Tb4b4b4]Tb4b4b4) Tff7b72>Tff7b72= T79c0ff40
Te6edf3holdTff7b72.Td2a8ffsetTb4b4b4(Tb4b4b4)
Tff7b72for Te6edf3thread Tff7b72in Te6edf3threadsTb4b4b4:
Te6edf3threadTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3timeoutTff7b72=T79c0ff5Tb4b4b4)
Tff7b72assert Te6edf3errors Tff7b72== Tb4b4b4[Tb4b4b4]
Tff7b72def Td2a8fftest_closed_handle_reopens_on_next_executeTb4b4b4(Tb4b4b4)Tb4b4b4:
T8b949e"""Another thread closing this handle must not stick HTTP on 500."""
Tff7b72with Te6edf3tempfileTff7b72.Td2a8ffTemporaryDirectoryTb4b4b4(Tb4b4b4) Tff7b72as Te6edf3temp_dirTb4b4b4:
Te6edf3db_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3temp_dirTb4b4b4, Ta5d6ff"Ta5d6ffreopen.dbTa5d6ff"Tb4b4b4)
Te6edf3provider Tff7b72= Te6edf3DatabaseProviderTb4b4b4(Te6edf3db_pathTb4b4b4)
Te6edf3providerTff7b72.Td2a8ffexecuteTb4b4b4(Ta5d6ff"Ta5d6ffCREATE TABLE t (id INTEGER PRIMARY KEY, val TEXT)Ta5d6ff"Tb4b4b4)
Te6edf3conn Tff7b72= Te6edf3providerTff7b72.Td2a8ffconnection
Te6edf3connTff7b72.Td2a8ffcloseTb4b4b4(Tb4b4b4)
Te6edf3providerTff7b72.Td2a8ffexecuteTb4b4b4(Ta5d6ff"Ta5d6ffINSERT INTO t (val) VALUES (?)Ta5d6ff"Tb4b4b4, Tb4b4b4(Ta5d6ff"Ta5d6ffokTa5d6ff"Tb4b4b4,Tb4b4b4)Tb4b4b4)
Te6edf3row Tff7b72= Te6edf3providerTff7b72.Td2a8fffetchoneTb4b4b4(Ta5d6ff"Ta5d6ffSELECT val FROM tTa5d6ff"Tb4b4b4)
Tff7b72assert Te6edf3rowTb4b4b4[Ta5d6ff"Ta5d6ffvalTa5d6ff"Tb4b4b4] Tff7b72== Ta5d6ff"Ta5d6ffokTa5d6ff"
Tff7b72def Td2a8fftest_sqlite_closed_database_is_retryableTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3exc Tff7b72= Te6edf3sqlite3Tff7b72.Td2a8ffProgrammingErrorTb4b4b4(Ta5d6ff"Ta5d6ffCannot operate on a closed database.Ta5d6ff"Tb4b4b4)
Tff7b72assert Te6edf3sqlite_error_is_retryableTb4b4b4(Te6edf3excTb4b4b4) Tff7b72is Tff7b72True
Tff7b72assert Te6edf3sqlite_error_is_retryableTb4b4b4(Tf85149RuntimeErrorTb4b4b4(Ta5d6ff"Ta5d6ffboomTa5d6ff"Tb4b4b4)Tb4b4b4) Tff7b72is Tff7b72False
Served by rngit 1.5.3 - Generated in 0.02s